#!/usr/bin/env python
# encoding: utf-8


"""
@time: 2016/11/14 下午8:17
"""
from functools import reduce
# 最值问题
from mathsolver.functions.base import *
from sympy import expand_trig, sin, cos, pi, degree, trigsimp, simplify, symbols, sqrt, fraction, expand
from mathsolver.functions.sanjiao import sanjiao_utils as su
from itertools import chain
from mathsolver.functions.budengshi import common_opers as co
from operator import itemgetter, add
from mathsolver.functions.sanjiao.huajian import trig_simplify
from mathsolver.functions.sanjiao.sanjiao_constants import TriangleKey
from mathsolver.functions.sanjiao import sanjiaoxing_utils as sjx_utils
from mathsolver.functions.sanjiao.triangle_constant import TARGET_TRIANGLE_EXPR_KEY, TRIANGLE_OP_CALED

SYMBOL_INTERVAL_SEARCH_KEY = sympify('symbol_search_key')


def _convert_trig_f(trig_f):
    """
    转变三角函数表达式为求最值得目标形式。主要围绕二倍角公式
    1 sin(2*x) 与 sin(x)**2 或者 cos(x)**2 同时出现 要进行降幂. 讲 sin(x)**2 或者 cos(x)**2 转变成 cos(2*x) 或者 sin(2*x)
    2 cos(2*x) 出现的时候 使用二倍角公式展开 然后使用换元
    3 如果可以化成标准的形式则不进行任何变换
    最终目标是变成可以化简成标准形式 或者 可以用换元方式【也就是三角函数的各个参数都相等】
    :param trig_f:
    :return:
    >>> _convert_trig_f('sin(2*x) + cos(x)**2')
    sin(2*x) + cos(2*x)/2 + 1/2
    >>> _convert_trig_f('2*cos(x)**2')
    cos(2*x) + 1
    """

    def _mon_converts(tmp_mon):
        """
        三角函数的等价变换
        :param tmp_mon:
        :return:
        """
        tmp_mon = sympify(tmp_mon)
        eq_mons = []
        quad_trig_reg = r'(sin|cos)\(.*\)\*\*2'
        single_trig_reg = r'(sin|cos)\(.*\)'
        # 首先判断是否二次的
        if re.search(quad_trig_reg, str(tmp_mon)):
            tmp_single_mon = re.search(single_trig_reg, str(tmp_mon)).group()
            _1, t_type, t_arg, _2 = su.simp_trig_info(tmp_single_mon)
            if t_type == sin:
                tmp_sub = (sin(t_arg) ** 2, (1 - cos(expand(2 * t_arg))) / 2)
                f1 = tmp_mon.subs(*tmp_sub)
                eq_mons.append(f1)
                # cos(x)**2 = 1- sin(x)**2; sin(x)**2 = 1 - cos(x)**2
                tmp_sub = (sin(t_arg) ** 2, 1 - cos(t_arg) ** 2)
                f2 = tmp_mon.subs(*tmp_sub)
                eq_mons.append(f2)
            elif t_type == cos:
                tmp_sub = (cos(t_arg) ** 2, (1 + cos(expand(2 * t_arg))) / 2)
                f1 = tmp_mon.subs(*tmp_sub)
                eq_mons.append(f1)
                # cos(x)**2 = 1- sin(x)**2; sin(x)**2 = 1 - cos(x)**2
                tmp_sub = (cos(t_arg) ** 2, 1 - sin(t_arg) ** 2)
                f2 = tmp_mon.subs(*tmp_sub)
                eq_mons.append(f2)
        elif re.search(single_trig_reg, str(tmp_mon)):  # 使用二倍角公式
            _1, t_type, t_arg, _2 = su.simp_trig_info(tmp_mon)
            if t_type == cos:  # 只有cos的时候才使用二倍角公式
                tmp_sub1 = (cos(t_arg), 2 * cos(t_arg / 2) ** 2 - 1)
                f1 = tmp_mon.subs(*tmp_sub1)
                eq_mons.append(f1)
                tmp_sub2 = (cos(t_arg), 1 - 2 * sin(t_arg / 2) ** 2)
                f2 = tmp_mon.subs(*tmp_sub2)
                eq_mons.append(f2)
        eq_mons.append(tmp_mon)
        return eq_mons

    def _trig_mon_type_args(tmp_trig_f):
        """
        三角函数中所有项的三角函数项的参数表达式列表
        :param tmp_trig_f:
        :return:
        """
        args = []
        f_mons = map(lambda _: _[0] * _[1], tmp_trig_f.as_coefficients_dict().items())
        quad_trig_reg = r'(sin|cos)\(.*\)\*\*2'
        single_trig_reg = r'(sin|cos)\(.*\)'
        for tmp_mon in f_mons:
            if tmp_mon.is_real:
                continue
            # 首先判断是否二次的
            if re.search(quad_trig_reg, str(tmp_mon)):
                tmp_single_mon = re.search(single_trig_reg, str(tmp_mon)).group()
                _1, t_type, t_arg, _3 = su.simp_trig_info(tmp_single_mon)
                args.append((t_type, t_arg, 2))
            elif re.search(single_trig_reg, str(tmp_mon)):  # 使用二倍角公式
                _1, t_type, t_arg, _3 = su.simp_trig_info(tmp_mon)
                args.append((t_type, t_arg, 1))
        return args

    trig_f = sympify(trig_f)
    if su.trig_is_simped(trig_f):  # 如果已经是最简形式了则不用化简了
        return trig_f
    trig_f_simp = simplify(trig_f)
    if su.trig_is_simped(trig_f_simp):
        return trig_f_simp
    mons = map(lambda _: _[0] * _[1], trig_f.as_coefficients_dict().items())
    eq_converts_list = [_mon_converts(mon) for mon in mons]
    converts_combins = co.combin_iters(*eq_converts_list)
    for combin in converts_combins:
        f = reduce(add, combin)
        sim_f = trig_simplify(f)
        if su.trig_is_simped(sim_f):  # 如果已经可以化成标准形式，则直接返回
            return sim_f
        f_type_args = _trig_mon_type_args(f)
        f_typs = map(lambda _: str(_[0]), f_type_args)
        f_args = map(lambda _: str(sympify(_[1])), f_type_args)
        f_degrees = map(lambda _: str(sympify(_[2])), f_type_args)
        if len(set(f_typs)) == 1 and len(set(f_args)) == 1:
            return f
        elif len(set(f_degrees)) == 1 and set(f_typs) == {'sin', 'cos'} and len(set(f_args)) == 1:
            return f
    return trig_f


def pub_convert_trig_f(trig_f):
    return _convert_trig_f(trig_f)


# 函数y=sinx+\\sqrt{3}cosx的最大值是().
# 只含有sin(x) cos(x)并且不含有分式。
# Input1 paramer1:三角函数表达式;
# Input2 paramer1:三角函数表达式; paramer2:最值文本
# Input3 paramer2:三角函数表达式; paramer3:x取值范围; paramer4:最值文本
class ZuiZhi001(BaseFunction):
    @staticmethod
    def classed(f):  # 是否属于该类别问题(只含有sin cos函数的问题)
        # symb = list(sympify(f).free_symbols)[0]
        f_arg = None
        symb = list(sympify(f).free_symbols)[0]
        if su.trig_is_simped(f):
            _1, _2, f_arg, _3 = su.simp_trig_info(f)
        src_f = f
        expand_f = expand_trig(f)
        mo, de = fraction(f)
        if not de.is_real:
            return False
        f2 = symb
        if f_arg:
            f2 = src_f.subs(((sin(f_arg), 1), (cos(f_arg), 1)))
        f3 = expand_f.subs(((sin(symb), 1), (cos(symb), 1)))
        if f2.is_real or f3.is_real:
            return True
        else:
            return False

    @staticmethod
    def aux_ang_f(f):  # 辅助角公式 a*sin(x) + b*cos(x) = sqrt(a**2 + b**2)*sin(x+theta) tan(theta) = b/a
        # sin(x)/2 + sqrt(3)*cos(x)
        symb = list(sympify(f).free_symbols)[0]
        simp_f, _ = su.trig_simp(f)
        trig_f, const = co.split_mons_const(simp_f)
        sined = False
        sin_mon = None
        cosed = False
        cos_mon = None
        for m, c in co.coefficients_dict(trig_f).items():
            if isinstance(m, sin):
                sined = True
                sin_mon = c * m
            elif isinstance(m, cos):
                cosed = True
                cos_mon = c * m
        if sined and cosed:
            a = su.trig_coeff(sin_mon)
            b = su.trig_coeff(cos_mon)
            f1 = sqrt(a ** 2 + b ** 2) * sin('%s + theta' % str(symb))
            return f1 + const, b / a
        return f, None

    def solver(self, *args):
        self.label.add('三角函数最值')
        _arg0 = args[0].sympify()
        _arg0 = list(co.flatten([_arg0]))
        if len(_arg0) == 1:
            f_l = 'y'
            f_r = _arg0[0]
        else:
            f_l, f_r = _arg0
        f_r = su.i_trig_simplify(f_r)
        x_symbol = sympify('x')
        if len(f_r.free_symbols) == 1:
            x_symbol = list(f_r.free_symbols)[0]
        x_interval = None
        if len(args) == 1:
            op_text = '范围'
        elif len(args) == 2 and isinstance(args[1], str):
            op_text = args[1]
        elif len(args) == 3 and isinstance(args[1], BaseInter) and isinstance(args[2], str):
            x_interval = args[1].interval
            op_text = args[2]
        if not ZuiZhi001.classed(f_r):
            raise Exception('Try Error!')
        symb = list(sympify(f_r).free_symbols)[0]
        simp_f = su.i_trig_simplify(f_r)
        src_simp_f = simp_f  # 未使用辅助角之前的表达式
        _1, _2, _3, _4 = su.simp_trig_info(simp_f)
        _, tan_value = ZuiZhi001.aux_ang_f(simp_f)
        if su.is_trig_f(_4) and not tan_value:  # 如果是复合的表达式 并且不能用辅助角公式
            raise Exception('Type Match Error')
        self.steps.append(['%s = %s' % (new_latex(f_l), new_latex(f_r)), ' = ' + new_latex(simp_f)])
        # 有一些不是特殊角的值需要使用辅助角公式

        simp_f, tan_value = ZuiZhi001.aux_ang_f(simp_f)
        if tan_value:  # 如果不是特殊角
            self.steps.append([' = ' + new_latex(simp_f), '(其中 \tan \theta = %s)' % new_latex(tan_value)])
        trig_f, _ = co.split_mons_const(simp_f)
        coef, trig_type, trig_arg, _ = su.simp_trig_info(trig_f)
        t_intl = Interval(-1, 1)
        if self.search(SYMBOL_INTERVAL_SEARCH_KEY):
            x_interval = self.search(SYMBOL_INTERVAL_SEARCH_KEY)
        elif self.search(symb):
            x_interval = self.search(symb)
        if x_interval:  # 如果有x的取值范围
            self.steps.append(['因为' + new_latex(x_symbol) + ' \\in ' + new_latex(x_interval), ''])
            x_left = x_interval.left
            x_right = x_interval.right
            arg_left = sympify(trig_arg).subs(x_symbol, x_left)
            arg_right = sympify(trig_arg).subs(x_symbol, x_right)
            if not arg_left.is_real:  # 如果使用了辅助角公式，那么在求变量取值范围时，就就会含有变量,所以我们要求出变量的取值范围
                _, sin_value, cos_value = su.aux_ang_f_v2(src_simp_f)
                other_angle_intl = su.angle_approx_interval(sin_value, cos_value)  # 辅助角的大致取值范围
                arg_intl = co.interval_add(x_interval, other_angle_intl)
                arg_left = arg_intl.left
                arg_right = arg_intl.right
            else:
                arg_intl = Interval(arg_left, arg_right, x_interval.left_open, x_interval.right_open)
            self.steps.append(['所以' + new_latex(sympify(trig_arg)) + '\\in ' + new_latex(arg_intl), ''])
            if trig_type == sin:
                sa_expr = 'k*pi+pi/2'
                sa_expr_values = map(sin, su.expr_value_list(sa_expr, arg_intl))
                sa_vs = [sin(arg_left), sin(arg_right)]
                sa_vs.extend(sa_expr_values)  # 修复bug
                sa_expr_falg_values = map(lambda _: (_, False), sa_expr_values)
                sa_flag_vs = [(sin(arg_left), arg_intl.left_open), (sin(arg_right), arg_intl.right_open)]
                all_values = list(chain(sa_expr_falg_values, sa_flag_vs))
                min_value, min_open = min(all_values, key=itemgetter(0))
                max_value, max_open = max(all_values, key=itemgetter(0))
                t_intl = Interval(min_value, max_value, left_open=min_open, right_open=max_open)
            elif trig_type == cos:
                sa_expr = 'k*pi'
                sa_expr_values = list(map(cos, su.expr_value_list(sa_expr, arg_intl)))
                sa_vs = [cos(arg_left), cos(arg_right)]
                sa_vs.extend(sa_expr_values)
                sa_expr_falg_values = list(map(lambda _: (_, False), sa_expr_values))
                sa_flag_vs = [(cos(arg_left), arg_intl.left_open), (cos(arg_right), arg_intl.right_open)]
                all_values = list(chain(sa_expr_falg_values, sa_flag_vs))
                min_value, min_open = min(all_values, key=itemgetter(0))
                max_value, max_open = max(all_values, key=itemgetter(0))
                t_intl = Interval(min_value, max_value, left_open=min_open, right_open=max_open)
            else:
                raise Exception('Type Match Error')
        trig_mon = trig_type(trig_arg)
        self.steps.append(['\\because -1 <= ' + new_latex(trig_f / coef) + ' <= 1', ''])
        sub_f = simp_f.subs(trig_mon, sympify('x'))
        domain = co.func_domain(sub_f, {'x': t_intl})
        fx = sympify('f(%s)' % str(symb))
        self.steps.append(
            ['\\therefore %s <= %s <= %s' % (new_latex(domain.left), new_latex(fx), new_latex(domain.right)), ''])
        if op_text.find('最大') >= 0:
            self.steps.append(['\\therefore 函数 %s = %s 的最大值是' % (new_latex(f_l), new_latex(f_r)), new_latex(domain.right)])
            self.output.append(BaseNumber(domain.right))
        elif op_text.find('最小') >= 0:
            self.steps.append(['\\therefore 函数 %s = %s 的最小值是' % (new_latex(f_l), new_latex(f_r)), new_latex(domain.left)])
            self.output.append(BaseNumber(domain.left))
        else:
            self.steps.append(['\\therefore 函数 %s = %s 的取值范围是' % (new_latex(f_l), new_latex(f_r)), new_latex(domain)])
            self.output.append(co.to_base_interval(domain))
        return self


# 二次三角函数的
# 函数y=sin^{2}x-sinx+3的最大值是()
# 函数y=2sin^{2}x+2cosx-3的最大值是()
class ZuiZhi003(BaseFunction):
    @staticmethod
    def trig_mons(trig_f):
        trig_f = sympify(trig_f)
        coefs_d = co.coefficients_dict(trig_f)
        linear_trig_mon = sympify('0')
        quad_trig_mon = sympify('0')
        for m, c in coefs_d.items():
            if m.is_real:
                continue
            elif degree(m) == 2:
                quad_trig_mon = c * m
            elif type(m) in (sin, cos):
                linear_trig_mon = c * m
        return linear_trig_mon, quad_trig_mon

    def solver(self, *args):
        self.label.add('二次三角函数最值')
        _arg0 = args[0].sympify()
        _arg0 = list(co.flatten([_arg0]))
        if len(_arg0) == 1:
            y_symbol = 'y'
            trig_f = _arg0[0]
        else:
            y_symbol, trig_f = _arg0
        trig_f = _convert_trig_f(trig_f)
        if len(args) == 1:
            op_text = '范围'
        else:
            op_text = args[1]
        x_symbol = list(trig_f.free_symbols)[0]
        _1, l_trig_type, l_trig_arg, _2 = su.simp_trig_info(trig_f)
        quad_trig = l_trig_type(l_trig_arg) ** 2
        sim_trig_f = trig_f.subs(trigsimp(1 - quad_trig), 1 - quad_trig)
        if trig_f != sim_trig_f:
            self.steps.append(['函数 %s = %s' % (new_latex(y_symbol), new_latex(trig_f)), ' = ' + new_latex(sim_trig_f)])
        t_symbol_sub = l_trig_type(l_trig_arg)
        self.steps.append(['令 t = %s' % new_latex(t_symbol_sub), '则 -1 <= t <= 1'])
        sim_trig_sub_f = sympify(str(sim_trig_f)).subs(t_symbol_sub, sympify('t'))
        values = []
        sim_trig_sub_f, top_point = co.top_point_expr(sim_trig_sub_f, sympify('t'))
        if top_point[0] in Interval(-1, 1):
            values.append(top_point)
        self.steps.append(['%s = %s ' % (new_latex(y_symbol), new_latex(trig_f)), ' = ' + new_latex(sim_trig_sub_f)])
        values.append((sympify('-1'), sim_trig_sub_f.subs('t', -1)))
        values.append((sympify('1'), sim_trig_sub_f.subs('t', 1)))
        max_value = max(values, key=itemgetter(1))
        min_value = min(values, key=itemgetter(1))
        if op_text.find('最大') >= 0:
            self.steps.append(
                ['故当 t = %s时, ' % new_latex(max_value[0]), '函数%s取得最大值为%s' % (new_latex(y_symbol), new_latex(max_value[1]))])
            self.steps.append(['故答案为%s' % new_latex(max_value[1]), ''])
            op_t_value = max_value[0]
            arg_op_value = sympify('a' + str(l_trig_type) + '(' + str(op_t_value) + ')')
            op_symbol_value = solve(arg_op_value - l_trig_arg)[0]
            self.output.append(BaseNumber(max_value[1]))
            self.output.append(BaseSymbolValue({x_symbol: op_symbol_value}))
        elif op_text.find('最小') >= 0:
            self.steps.append(
                ['故当 t = %s时, ' % new_latex(min_value[0]), '函数%s取得最小值为%s' % (new_latex(y_symbol), new_latex(min_value[1]))])
            self.steps.append(['故答案为%s' % new_latex(min_value[1]), ''])
            self.output.append(BaseNumber(min_value[1]))
        else:
            result_intl = Interval(min_value[1], max_value[1])
            self.steps.append(
                ['故当 t = %s时, ' % new_latex(min_value[0]),
                 '函数%s的取值范围为%s' % (new_latex(y_symbol), new_latex(result_intl))])
            self.steps.append(['故答案为%s' % new_latex(result_intl), ''])
            self.output.append(co.to_base_interval(result_intl))
        return self


# 在△ABC中,B=60°,AC=\\sqrt{3},则AB+2BC的最大值为().
class ZuiZhi004(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数最值')
        # 先决条件检验
        if not self.search(TriangleKey):
            raise Exception('Type Match Error')
        eqs = sjx_utils.known_triangle_eqs(self.known)
        eq_list = eqs.sympify()
        if len(eq_list) != 2:
            raise Exception('Type Match Error')
        new_eq_list = []
        for tmp_eq in eq_list:
            new_eq_list.append(sjx_utils.process_cond_eq(BaseEq(tmp_eq)).sympify())
        eq1, eq2 = new_eq_list
        eq1_l, eq1_r = eq1
        eq2_l, eq2_r = eq2
        eq1_f = eq1_l - eq1_r
        eq2_f = eq2_l - eq2_r
        eq1_symbs = list(eq1_f.free_symbols)
        eq2_symbs = list(eq2_f.free_symbols)
        if len(eq1_symbs) != 1 or len(eq2_symbs) != 1:
            raise Exception('Type Match Error')
        eq1_symb = eq1_symbs[0]
        eq2_symb = eq2_symbs[0]
        if str(eq1_symb).lower() != str(eq2_symb).lower():
            raise Exception('Type Match Error')
        self.steps.append(['\\because ' + BaseEq(eq1).printing(), ';' + BaseEq(eq2).printing()])
        self.steps.append(
            ['由正弦定理得: ' + new_latex(sympify('a/sin(A)')) + '=' + new_latex(sympify('b/sin(B)')) + '=' + new_latex(
                sympify('C/sin(C)')),
             ''])
        cond_side = sympify(str(eq2_symb).lower())
        cond_angle = sympify(str(eq2_symb).upper())
        side1, side2 = FiniteSet('a', 'b', 'c') - FiniteSet(str(cond_side))
        angle1, angle2 = sympify(str(side1).upper()), sympify(str(side2).upper())
        if str(eq1_symbs[0]) in ['A', 'B', 'C']:
            cond_angle_value = solve(eq1_f)[0]
            cond_side_value = solve(eq2_f)[0]
        else:
            cond_angle_value = solve(eq2_f)[0]
            cond_side_value = solve(eq1_f)[0]
        ratio_value = (cond_side / sin(cond_angle)).subs(((cond_side, cond_side_value), (cond_angle, cond_angle_value)))
        side1_value = ratio_value * sin(angle1)
        side2_value = ratio_value * sin(angle2)
        self.steps.append(
            ['\\therefore %s=%s; %s=%s' % (new_latex(side1), new_latex(side1_value), new_latex(side2), new_latex(side2_value)), ''])
        src_target_f = args[0].sympify()
        target_f = sjx_utils.process_triangle_expr(src_target_f)
        target_f2 = target_f.subs(((side1, side1_value), (side2, side2_value)))
        self.steps.append(['\\therefore %s=%s' % (new_latex(src_target_f), new_latex(target_f)), '=' + new_latex(target_f2)])
        self.steps.append(['\\because ' + BaseEq(['A+B+C', 'pi']).printing(), ''])
        angle2_sub = pi - cond_angle_value - angle1
        target_f3 = target_f2.subs(angle2, angle2_sub)
        self.steps.append(['\\therefore %s = %s' % (new_latex(target_f2), new_latex(target_f3)), ''])
        target_f3 = expand_trig(target_f3)
        op_text = args[1]
        op_result = SanJiaoHanShuZuiZhi(verbose=True).solver(BaseEq(['y', target_f3]), op_text)
        self.steps.extend(op_result.steps)
        self.steps.append(['求得值为', new_latex(op_result.output[0])])
        self.output.append(op_result.output[0])
        return self


# ABC的三个内角为A、B、C,求当A为何值时,cosA+2cos\\frac{B+C}{2}取得最大值,并求出这个最大值.
class ZuiZhi005(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数最值')
        if len(args) == 1 and isinstance(args[0], str):
            y_symbol = 'y'
            f_expr = list(self.search(TARGET_TRIANGLE_EXPR_KEY))[0]
            text = args[0]
        else:
            y_symbol = 'y'
            f_expr = sympify(args[0].sympify())
            text = args[1]
        f_expr = f_expr.subs(sjx_utils.get_triangle_subs())
        f2 = _convert_trig_f(f_expr)
        x_symbol = list(f2.free_symbols)[0]
        self.steps.append([new_latex(f_expr) + '=' + new_latex(f2), ''])
        op_value = SanJiaoHanShuZuiZhi().solver(BaseEq([y_symbol, f2]), text)
        self.steps.extend(op_value.steps)
        self.output.append(op_value.output[0])
        x_op_value = list(op_value.output[1].sympify()[x_symbol])[0]
        self.output.append(BaseSymbolValue({x_symbol: x_op_value}))
        return self


# sinx±cosx与sinxcosx，sin2x的关系
# style1 Input paramer1:三角函数; paramer2:文本(最大值/最小值/取值范围) Ouput 函数的值域
class ZuiZhi006(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数最值')
        self.label.add('sinx±cosx与sinxcosx，sin2x的关系')
        arg1 = args[0]
        f_symbol, f_expr = arg1.sympify()
        symb = list(f_expr.free_symbols)[0]
        e1 = sin(symb) * cos(symb)
        e1_ = sin(2 * symb)
        e2 = sin(symb) + cos(symb)
        e3 = sin(symb) - cos(symb)
        _t = sympify('t')
        if (f_expr.has(e1) or f_expr.has(e1_)) and f_expr.has(e2):
            e1_sub = (_t ** 2 - 1) / 2
            f2 = sympify(str(f_expr)).subs(e2, _t)
            t_interval = SanJiaoHanShuZuiZhi(known=self.known).solver(BaseEq(['y', e2]), '取值范围').output[0].interval
        elif (f_expr.has(e1) or f_expr.has(e1_)) and f_expr.has(e3):
            f2 = sympify(str(f_expr)).subs(e3, _t)
            t_interval = SanJiaoHanShuZuiZhi(known=self.known).solver(BaseEq(['y', e3]), '取值范围').output[0].interval
            e1_sub = (1 - _t ** 2) / 2
        else:
            raise Exception('Type Match Error')
        f3 = f2.subs(e1, e1_sub).subs(e1_, 2 * e1_sub)
        self.steps.append(['令 t = ' + new_latex(e2), '则' + new_latex(e1) + '=' + new_latex(e1_sub)])
        self.steps.append(['所以y = ' + new_latex(f_symbol) + '=' + new_latex(f3), ''])
        from mathsolver.functions.hanshu.zhiyu import HanShuZhiYu
        op_obj = HanShuZhiYu().solver(BaseEq(['y', f3]), t_interval)
        for ll in op_obj.label:
            self.label.add(ll)
        arg2 = args[1]
        result_intl = op_obj.output[0].value
        if arg2.find('最大值') >= 0:
            self.steps.append(['求得最大值为:', new_latex(result_intl.right)])
        elif arg2.find('最小值') >= 0:
            self.steps.append(['求得最小值为:', new_latex(result_intl.left)])
        else:
            self.steps.append(['求得值域为:', new_latex(result_intl)])
        return self


# 使用Mathematic求最值
# style1 Input1:paramer1 函数 paramer2:最值文本
class ZuiZhiWithMatheMatic(BaseFunction):
    def solver(self, *args):
        self.label.add('三角函数值域')
        arg0 = args[0]
        arg0 = list(co.flatten([arg0.sympify()]))
        if len(arg0) == 1:
            f_symbol = sympify('y')
            f_expr = arg0[0]
        else:
            f_symbol, f_expr = arg0
        from mathsolver.functions.hanshu.zhiyu import HanShuZhiYu
        _x = sympify('x')
        f_intl = HanShuZhiYu().solver(BaseEq([f_symbol, f_expr]), self.search(_x)).output[0].value
        text = args[1]
        if text.find('最大值') >= 0:
            self.output.append(BaseNumber(f_intl.right))
        elif text.find('最小值') >= 0:
            self.output.append(BaseNumber(f_intl.left))
        else:
            self.output.append(co.to_base_interval(f_intl))
        return self


# 三角形的最值问题
# Note: Known中会有三角形的标志key, 以及三角形的一些变量的值，比如边的值，角的值
# style1 Paramer1:三角形的变量表达式函数; paramer2: 最值文本(最大值/最小值)
class SanJiaoXingZuiZhi(BaseFunction):
    def _solver1(self, *args):
        return ZuiZhi005(known=self.known).solver(*args)

    def _solver001(self, *args):
        from mathsolver.functions.sanjiao.sanjiaoxing_zuizhi import JieSanJiaoXingZuiZhiWenTi
        return JieSanJiaoXingZuiZhiWenTi(known=self.known).solver(*args)

    def _solver2(self, *args):
        from mathsolver.functions.sanjiao.sanjiaoxing_zuizhi import SanJiaoXingJiaoHanShuFanWei
        return SanJiaoXingJiaoHanShuFanWei(known=self.known).solver(*args)

    # 已知三角形的中的一些条件，根据问题来搜寻答案
    # Input paramer1:BaseEq(函数表达式);  paramer2:取值范围
    def _solver3(self, *args):
        arg1, arg2 = args
        if isinstance(arg1, BasePoly):
            f_expr = arg1.sympify()
        else:
            f_symbol, f_expr = arg1.sympify()
        f_expr = f_expr.subs(sjx_utils.get_triangle_subs())
        _A, _B, _C = symbols('A, B, C')
        symbs = f_expr.free_symbols
        symbs = list(map(lambda _: sympify(str(_).upper()), symbs))
        if len(symbs) == 2 and su.i_is_subset(symbs, {_A, _B, _C}):
            _angle = list({_A, _B, _C} - set(list(symbs)))[0]  # 根据known中的条件, 要求的角
            from mathsolver.functions.sanjiao.sanjiao_objects import JieSanJiaoXing
            tmp_solver = JieSanJiaoXing(known=self.known).solver(BasePoly(_angle))
            self.steps.extend(tmp_solver.steps)
            _angle_value = list(tmp_solver.output[0].sympify()[_angle])[0]
            self.known[_angle] = _angle_value
            from mathsolver.functions.sanjiao.sanjiaoxing_zuizhi import SanJiaoXingJiaoHanShuFanWei
            tmp_solver = SanJiaoXingJiaoHanShuFanWei(known=self.known).solver(arg1, arg2)
            self.steps.extend(tmp_solver.steps)
            self.output.extend(tmp_solver.output)
            return self
        else:
            raise Exception('Type Match Error')

    def solver(self, *args):
        if not sjx_utils.is_in_triangle(self.known):
            raise Exception('Not in the triangle')
        # 为了避免循环调用 所以当第一次调用求三角函数最值得时候，设置一个标志，表示已经进入到求三角函数最值中，这样如果在循环进入就中断
        if self.known.get(TRIANGLE_OP_CALED, False):
            raise Exception('Cycle call')  # 循环调用则退出
        else:  # 如果是第一次调用 则设置标志
            self.known[TRIANGLE_OP_CALED] = True

        _solvers = [self._solver001, self._solver2, self._solver3, self._solver1]
        _solver = None
        for _s in _solvers:
            try:
                _solver = _s().solver(*args)
                break
            except Exception:
                pass
        if not _solver:
            raise Exception('Can\'t solve the optimum value of the function')
        _solver.label.add('解三角形')
        _solver.label.add('求三角函数最值')
        return _solver


class JieSanJiaoXingZhongZuiZhi(SanJiaoXingZuiZhi):
    pass


class SanJiaoHanShuZuiZhi(BaseFunction):
    CLS = [ZuiZhi003, ZuiZhi001, ZuiZhi004, ZuiZhi006, SanJiaoXingZuiZhi, ZuiZhiWithMatheMatic]

    def solver(self, *args):
        """
        #015 函数y=3sinx+2cosx的最小值是()【OK】
        IF:
            question = "OF(sinfunc,最小值)"
        THEN:
            SanJiaoHanShuZuiZhi(question_sinfunc, question_inter, question_text) 第二个question_inter是后面加入的,
            为了保证程序的不变形 所以要做特殊处理,将 question_inter 加入到known中
            比如 函数y = \\sin x + \\sqrt {3} \\cos x在区间[0, \\frac{π }{2} ]的最小值为
        """
        tmp_args = [arg for arg in args]
        if len(args) >= 2 and not tmp_args[1]:  # 如果为None
            del tmp_args[1]
        elif len(args) >= 2 and isinstance(tmp_args[1], BaseInter):
            intl = args[1].interval
            del tmp_args[1]
            self.known[SYMBOL_INTERVAL_SEARCH_KEY] = intl
        solve_r = None
        # if sjx_utils.is_in_triangle(self.known) and not self.known.get(TRIANGLE_OP_CALED, False):  # 避免循环引用
        #     self.known[TRIANGLE_OP_CALED] = True
        #     return SanJiaoXingZuiZhi(known=self.known).solver(*tmp_args)
        for cl in SanJiaoHanShuZuiZhi.CLS:
            try:
                # solve_r = cl(verbose=True)
                # solve_r.known = self.known
                solve_r = cl(known=self.known)
                solve_r = solve_r.solver(*tmp_args)
                solve_r.label.add('三角函数最值')
                solve_r.label.add('三角函数化简')
                break
            except Exception:
                solve_r = None
        if not solve_r:
            raise Exception('Type Match Error')
        return solve_r


# 已知三角函数的最值求参数
# style1 Input paramer1:三角函数; paramer2: 最值文本; paramer3 最值
# style2 Input paramer1:三角函数; paramer2: 最值文本; paramer3 最值; paramer4:区间baseInner
class SanJiaoHanShuZuiZhiQiuCan(BaseFunction):
    def solver(self, *args):
        self.label.add('由三角函数最值求参数')
        if len(args) == 3:
            arg1, arg2, arg3 = args
            arg4 = None
        elif len(args) == 4:
            arg1, arg2, arg3, arg4 = args
        else:
            raise Exception('Illegal parameters')
        text = arg2
        op_text = '最大值' if text.find('最大值') >= 0 else '最小值'
        op_type = 'max' if op_text == '最大值' else 'min'
        op_value = arg3.sympify()
        f_symbol, f_expr = arg1.sympify()
        f_expr_simp = su.i_trig_simplify(f_expr)  # 化简
        t_coef, t_type, t_arg, t_const = su.simp_trig_info(f_expr_simp)
        _x, _k = symbols('x, k')
        x_interval = self.search(_x)
        if arg4:
            x_interval = arg4.interval
        eqs = []
        if t_type == sin:
            if op_type == 'max':
                _eq = BaseEq([t_arg, 2 * _k * pi + pi / 2])
                _x_v = co.isolve_eq2(_eq)[0]
                if su.expr_value_list(_x_v, x_interval):
                    eqs.append([t_coef + t_const, op_value])
                else:
                    bound_values = [t_type(t_arg).subs(_x, x_interval.left), t_type(t_arg).subs(_x, x_interval.right)]
                    max_v = max(bound_values)
                    eqs.append([t_coef * max_v + t_const, op_value])
            else:
                _eq = BaseEq([t_arg, 2 * _k * pi + 3 * pi / 2])
                _x_v = co.isolve_eq2(_eq)[0]
                if su.expr_value_list(_x_v, x_interval):
                    eqs.append([-t_coef + t_const, op_value])
                else:
                    bound_values = [t_type(t_arg).subs(_x, x_interval.left), t_type(t_arg).subs(_x, x_interval.right)]
                    max_v = min(bound_values)
                    eqs.append([t_coef * max_v + t_const, op_value])
        elif t_type == cos:
            if op_type == 'max':
                _eq = BaseEq([t_arg, 2 * _k * pi])
                _x_v = co.isolve_eq2(_eq)[0]
                if su.expr_value_list(_x_v, x_interval):
                    eqs.append([t_coef + t_const, op_value])
                else:
                    bound_values = [t_type(t_arg).subs(_x, x_interval.left), t_type(t_arg).subs(_x, x_interval.right)]
                    max_v = max(bound_values)
                    eqs.append([t_coef * max_v + t_const, op_value])
            else:
                _eq = BaseEq([t_arg, 2 * _k * pi + pi])
                _x_v = co.isolve_eq2(_eq)[0]
                if su.expr_value_list(_x_v, x_interval):
                    eqs.append([-t_coef + t_const, op_value])
                else:
                    bound_values = [t_type(t_arg).subs(_x, x_interval.left), t_type(t_arg).subs(_x, x_interval.right)]
                    max_v = min(bound_values)
                    eqs.append([t_coef * max_v + t_const, op_value])
        self.steps.append(['由题意可知:', BaseEq(eqs[0]).printing()])
        param = sympify(co.eqs_symbs([eqs[0]])[0])
        param_value = co.isolve_eq2(BaseEq(eqs[0]))[0]
        self.output.append(BaseEq(eqs[0]))
        self.output.append(BaseSymbolValue({param: param_value}))
        return self


if __name__ == '__main__':
    pass
